package com.yzh.openai.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @EnableAsync 注解可以有以下几个作用：
 * 启用异步执行：它允许你以异步方式执行方法，提高应用程序的响应性和吞吐量。
 * 配置异步执行的行为：通过与其他注解（如 @Async、@EnableAsync 的参数）结合使用，可以配置异步执行的各种行为，例如线程池、超时时间、异常处理等。
 * 组件扫描：@EnableAsync 会扫描指定的包路径（通过 @ComponentScan 注解指定）以查找异步执行的方法。
 * 集成其他异步框架：@EnableAsync 还可以与第三方异步框架（如 AsyncAPI）集成，以支持更复杂的异步用例。
 */
@Slf4j
@EnableAsync
@Configuration
@EnableConfigurationProperties(ThreadPoolConfigProperties.class)
public class ThreadPoolConfig {
    /**
     * 线程名称
     */
    private static final AtomicInteger threadNumber = new AtomicInteger();
    @Bean
    @ConditionalOnMissingBean(ThreadPoolExecutor.class) //若指定类型的Bean未注册则会注册，确保仅有一个线程池在运行
    public ThreadPoolExecutor threadPoolExecutor(ThreadPoolConfigProperties properties) {
        //实例化拒绝策略
        RejectedExecutionHandler handler;
        switch (properties.getPolicy()){
            case "AbortPolicy":
                handler = new ThreadPoolExecutor.AbortPolicy();
                break;
            case "DiscardPolicy":
                handler = new ThreadPoolExecutor.DiscardPolicy();
                break;
            case "DiscardOldestPolicy":
                handler = new ThreadPoolExecutor.DiscardOldestPolicy();
                break;
            case "CallerRunsPolicy":
                handler = new ThreadPoolExecutor.CallerRunsPolicy();
                break;
            default:
                handler = new ThreadPoolExecutor.AbortPolicy();
                break;
        }
        //创建线程池
        return new ThreadPoolExecutor(properties.getCorePoolSize(),
                properties.getMaxPoolSize(),
                properties.getKeepAliveTime(), 
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(properties.getBlockQueueSize()),
                (runnable) -> new Thread(runnable, threadNumber.getAndAdd(1) + "号线程"),
                handler);
    }
}
